/**
 * 
 */
package com.un.ebs.businessObject.service.impl;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.un.ebs.core.UserContextService;
import com.un.ebs.core.metadata.*;
import com.un.ebs.core.util.PackageUtil;
import com.un.ebs.sys.service.impl.TableWapper;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.un.ebs.core.enums.ColumnRefTypeEnum;
import com.un.ebs.core.enums.DataTypeEnum;
import com.un.ebs.core.enums.RequestArgEnum;
import com.un.ebs.sys.domain.Column;
import com.un.ebs.sys.domain.Table;
import com.un.ebs.sys.enums.DisplayEnums;
import com.un.ebs.sys.enums.FunctionsEnums;
import com.un.ebs.sys.mapper.ColumnMapper;
import com.un.ebs.businessObject.service.RelAddService;
import com.un.ebs.businessObject.service.RelService;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * 通用新增扩展
 * 
 * @author caoyinfeng
 * @date 2021-02-04
 */
@Slf4j
@Service("RelAddExtServiceImpl")
public class RelAddExtServiceImpl extends BaseBusinessObjectService implements RelAddService {

	@Autowired
	private ColumnMapper columnMapper;

	@Autowired
	private RelService relService;

	@Override
	public FunctionInfo getAddFunc(Table table) {
		FunctionInfo func = new FunctionInfo();
		String url = FunctionsEnums.ADD.getUrl();
		String desc = FunctionsEnums.ADD.getDesc();
		List<RequestMethod> method = Arrays.asList(FunctionsEnums.ADD.getRequestMethod());

		func.setUrl(String.format(url, table.getId()));
		func.setDescription(desc);
		func.setMethod(method);
		func.setName(table.getTableName());

		TableWapper tableWapper = new TableWapper(); // 子类转父类
		try {
			BeanUtils.copyProperties(tableWapper, table);
		} catch (IllegalAccessException | InvocationTargetException e) {
			log.error("getAddFunc转化table异常 error={}", e.getMessage());
			e.printStackTrace();
		}
		List<Table> tables = relService.getDbTables(table); // 获取所有表格
		relService.recursiveTable(tableWapper, tables, table.getId());

		Inner pInner = new Inner();
		this.procTableColumn(null, pInner, tableWapper, true); // 主表数据

		func.setRequest(pInner.getA());
		func.setResponse(pInner.getB());
		return func;
	}

	@Getter
	@Setter
	class Inner {
		/** 请求参数 */
		List<RequestArg> a = new ArrayList<>();
		/** 响应参数 */
		List<MetadataField> b = new ArrayList<>();
	}

	/**
	 * 处理表字段
	 * 
	 * @param arg   父级参数
	 * @param inner 父级inner
	 * @param table 父级table
	 */
	private void procTableColumn(RequestArg arg, Inner inner, TableWapper table, boolean flag) {
		if (flag == true) {// 是顶级
			// 请求参数
			List<RequestArg> requestArgs = new ArrayList<>();
			// 返回参数
			List<MetadataField> metadataFields = new ArrayList<>();

			LambdaQueryWrapper<Column> qw = Wrappers.lambdaQuery();
			qw.eq(Column::getTableId, table.getId());
			qw.orderByAsc(Column::getSort);
			List<Column> columns = columnMapper.selectList(qw);

			columns = columns.stream().filter(x -> !DisplayEnums.getColumnNameList().contains(x.getColumnName()))
					.collect(Collectors.toList()); // 过滤支持相关字段
			for (Column column : columns) {
				if (!column.getIsPk()) {
					RequestArg requestArg = new RequestArg();
					requestArg.setRequestType(RequestArgEnum.RequestBody);
					requestArg.setName(column.getColumnName());
					requestArg.setDisplayName(column.getColumnDesc());
					requestArg.setDataType(column.getColumnType());
					requestArg.setIsArray(0);
					requestArg.setNull(column.getIsNullable());
					requestArg.setLength(column.getLength());

					requestArgs.add((RequestArg) convertToArg(column, requestArg));
				}

				if (column.getIsPk()) {
					MetadataField metadataField = new MetadataField();
					metadataField.setName(column.getColumnName());
					metadataField.setDisplayName(column.getColumnDesc());
					metadataField.setDataType(column.getColumnType());
					metadataField.setIsArray(0);

					metadataFields.add(convertToArg(column,metadataField));

				}
			}

			inner.getA().addAll(requestArgs);
			inner.getB().addAll(metadataFields);
		}

		// 处理子级对象
		List<TableWapper> list = table.getChilds();
		if (list != null && !list.isEmpty()) {
			for (TableWapper childTb : list) {
				RequestArg refRequestArg = procChildData(arg, inner, table.getId(), table.getTableName(), childTb);
				// 递归子表
				this.procTableColumn(refRequestArg, inner, childTb, false);
			}
		}
	}

	/**
	 * 处理下一级数据 只返回父级对象的id
	 * 
	 * @param inner     父表inner信息
	 * @param tableId   父表id
	 * @param tableName 父亲name
	 * @param table     子表
	 */
	private RequestArg procChildData(RequestArg arg, Inner inner, String tableId, String tableName, TableWapper table) {
		RequestArg refRequestArg = null;
		LambdaQueryWrapper<Column> qw = Wrappers.lambdaQuery();
		qw.eq(Column::getTableId, table.getId());
		List<Column> columns = columnMapper.selectList(qw);
		columns = columns.stream().filter(x -> !DisplayEnums.getColumnNameList().contains(x.getColumnName()))
				.collect(Collectors.toList()); // 过滤支持相关字段

		// 请求参数
		List<MetadataField> requestArgs = new ArrayList<>();
		// 查出与父级表名一样的外键字段名称集合
		Set<String> refs = columns.stream()
				.filter(x -> (x.getRefTableName() != null && x.getRefTableName().equals(tableName))
						&& (x.getRefType() != null && ColumnRefTypeEnum.FK.equals(x.getRefType()))
						&& x.getRefColumnName() != null)
				.map(x -> x.getColumnName()).collect(Collectors.toSet());
		String refColumnName = refs.stream().findFirst().orElse(null);
		if (refColumnName != null) {
			for (Column column : columns) {
				// 非主键、非外键列
				if (!column.getIsPk() && !ColumnRefTypeEnum.FK.equals(column.getRefType())) {
					// 新增：请求参数为外键之外的参数
					MetadataField requestArg = new RequestArg();
					requestArg.setName(column.getColumnName());
					requestArg.setDisplayName(column.getColumnDesc());
					requestArg.setDataType(column.getColumnType());
					requestArg.setIsArray(0);
					requestArg.setNull(column.getIsNullable());
					requestArg.setLength(column.getLength());
					requestArgs.add(convertToArg(column,requestArg));
				}
			}

			// 新增外键虚拟列（默认只有一个外键）
			refRequestArg = new RequestArg();
			refRequestArg.setRequestType(RequestArgEnum.RequestBody);
			refRequestArg.setName(String.format("ref_%s|%s", table.getId(), refColumnName));
			refRequestArg.setDisplayName(refRequestArg.getName()); // 显示名称暂取Name
			refRequestArg.setDataType(DataTypeEnum.OBJECT); // 对象
			refRequestArg.setIsArray(1);
			refRequestArg.setNull(false); // 外键，默认为false
			refRequestArg.setLength(0); // 外键，默认为0
			refRequestArg.setChildField(requestArgs); // 子级对象

			if (arg == null) {
				inner.getA().add(refRequestArg);
			} else {
				List<MetadataField> fields = arg.getChildField();
				if (fields == null) {
					fields = new ArrayList<>();
				}

				fields.add(refRequestArg);
			}
		}

		return refRequestArg;
	}


}
